//
//	(c) 2009 Andrew Kalmacky
//

#ifndef _AK_LTM_H_
#define _AK_LTM_H_

#include <new>
#include <algorithm>
#include "../logger/logger.h"
#include "../atomic/atomic_lock.h"
#define no_throw throw()

#ifdef MSVC
#define TLS_VAR(N) _declspec(thread) N
#else
#define TLS_VAR(N) __thread N
#endif

namespace ak
{
	namespace ltm
	{
		extern TLS_VAR(bool in_move);

		class Object;
		class WeakBlock;

		class copy_solver
		{
		public:
			copy_solver();
			~copy_solver();
		};

		class Object
		{
			friend class this_protector_t;
		public:
			Object()
			{
			}

			Object(const Object& src)
				: _ptr_counter()
				, _weak()
			{
			}

			Object* _lock() no_throw
			{
				if (this)
					++_ptr_counter;
				return this;
			}

			const Object* _lock() const no_throw
			{
				if (this)
					++_ptr_counter;
				return this;
			}
			void _unlock() no_throw;
			void _copy_to_ref(Object*& dst) const;

			Object* _get_weak() const
			{
				return this ? _inner_get_weak() : NULL;
			}
			Object* _get_target() const // returns prelocked object
			{
				return this ? _inner_get_target() : NULL;
			}

		protected:
			static const size_t OBJ_OWNED = 0x80000000;

			bool is_ptr_counter_empty() const
			{
				return (_ptr_counter & ~OBJ_OWNED) == 0;
			}
			mutable tm::atomic<size_t> _ptr_counter;
			mutable tm::atomic<WeakBlock*> _weak;

			virtual void delete_this();
			virtual void copy(Object*& dst) const =0;

			virtual Object* _inner_get_weak() const;
			virtual Object* _inner_get_target() const; // returns prelocked object

			bool _acquire_ownership() const no_throw;
			bool _can_be_deleted();
			~Object();

			Object* get_weak_as_proxy() const
			{
				return const_cast<Object*>(_lock());
			}
			Object* copy_as_shared() const
			{
				return const_cast<Object*>(_lock());
			}
		};

		class this_protector_t
		{
			Object* p;
		public:
			this_protector_t(Object* p) : p(p) { ++p->_ptr_counter; }
			~this_protector_t() { --p->_ptr_counter; }
		};

		class SharedObject: public Object
		{
		public:
			virtual void copy(Object*& dst) const;
		};

		class WeakBlock: public Object
		{
		public:
			WeakBlock(Object* target)
			{
				_weak.store(static_cast<WeakBlock*>(target), tm::memory_order_relaxed);
			}
			~WeakBlock()
			{
				Log::ltm::info::assert(_weak == NULL, T_("weak block destroyed prior to target object"));
			}
			virtual void copy(Object*& dst) const;

		protected:
			virtual void delete_this();

			virtual Object* _inner_get_weak() const; // prelocked
			virtual Object* _inner_get_target() const; // prelocked
		};

		inline Object::~Object()
		{
			_weak->_unlock();
		}

		struct sync
		{
			typedef tm::atomic<Object*> type;
			static Object*& get_ref(type& t) { return t.val; }
			static Object* swap(type& p, Object* new_val)
			{
				atomic_lock<Object> l(p);
				Object* r = l;
				l = new_val;
				return r;
			}
			static atomic_lock<Object> lock(type& p) { return p; }
		};

		struct no_sync
		{
			typedef Object* type;
			static Object*& get_ref(type& t) { return t; }
			static Object* swap(type& p, Object* new_val)
			{
				Object* r = p;
				p = new_val;
				return r;
			}
			static Object* lock(type& p) { return p; }
		};

		template <typename T, typename SYNC = no_sync> class master;
		template <typename T, typename SYNC = no_sync> class weak;
		template <typename T> class pin;

		template <typename T, typename SYNC>
		class master
		{
			friend class pin<T>;
			friend class weak<T, sync>;
			friend class weak<T, no_sync>;

			//template<typename U> friend class weak<T, U>;
			mutable typename SYNC::type p;

		public:
			master() no_throw :p() {}

			master(T* src)
			{
				src->_copy_to_ref(SYNC::get_ref(p)); // this acquires ownership for newly constructed, or makes a deep copy if some 'this' passed
			}
			master(const pin<T>& src)
			{
				src->_copy_to_ref(SYNC::get_ref(p)); // pin::op-> makes Object* and... see above
			}
			master(const weak<T>& src)
			{
				src->_copy_to_ref(SYNC::get_ref(p)); // weak should be dereferenced to a pin, using pin<T> weak<T>::op->
			}
			master(const master<T, SYNC>& src)
			{
				if (::ak::ltm::in_move) // src.p is in void area, so no locking required
					SYNC::get_ref(p) = SYNC::get_ref(src.p);
				else
					src->_copy_to_ref(SYNC::get_ref(p)); // yes, src should be locked for whole _copy_to_ref operation, here it is done with pin<T> master<T>::op->
			}

			~master() no_throw
			{
				p->_unlock();
			}

			pin<T> operator-> () const no_throw { return *this; } // let the pin constructor make the real locks
			operator void* /* bool */ () const no_throw { return p; }

			template<typename SRC>
			master<T, SYNC>& operator= (const SRC& src)
			{
				Object* temp;
				src->_copy_to_ref(temp);
				SYNC::swap(p, temp)->_unlock();
				return *this;
			}

			master<T, SYNC>& operator= (const master<T>& src)
			{
				if (&src != this)
					operator= (pin<T>(src));
				return *this;
			}

			void reset() no_throw
			{
				SYNC::swap(p, NULL)->_unlock();
			}

			template<typename BASE>
			operator const master<BASE, SYNC>& () const no_throw
			{
				BASE* t_should_be_convertible_to_base = static_cast<T*>(NULL);
				return reinterpret_cast<const master<BASE, SYNC>&>(*this);
			}

			template<typename A> friend void unsafe_swap(master<A>& a, master<A>& b);
			template<typename A> friend int compare(const master<A>& a, const master<A>& b);
			template<typename A> friend bool operator== (const master<A>& a, const master<A>& b);
		};

		template<typename T, typename SYNC>
		class weak
		{
			friend class pin<T>;
			mutable typename SYNC::type p;

		public:
			weak() no_throw :p() {}

			weak(const weak<T, SYNC>& src)
			{
				if (::ak::ltm::in_move) // src.p is in void area, so no locking required
					SYNC::get_ref(p) = SYNC::get_ref(src.p);
				else
					SYNC::lock(src.p)->_copy_to_ref(SYNC::get_ref(p));
			}

			template<typename SRC_SYNC>
			weak(const weak<T, SRC_SYNC>& src)
			{
				SRC_SYNC::lock(src.p)->_copy_to_ref(SYNC::get_ref(p));
			}

			template<typename SRC_SYNC>
			weak(const master<T, SRC_SYNC>& src)
				: p(SRC_SYNC::lock(src.p)->_get_weak())
			{
			}
			weak(const pin<T>& src)
				: p(src->_get_weak())
			{
			}
			~weak() no_throw
			{
				p->_unlock();
			}

			template<typename SRC>
			weak<T, SYNC>& operator= (const SRC& src)
			{
				weak<T> temp(src);
				temp.p = SYNC::swap(p, temp.p);
				return *this;
			}

			weak<T, SYNC>& operator= (const weak<T, SYNC>& src)
			{
				if (this != &src)
				{
					weak<T> temp(src);
					temp.p = SYNC::swap(p, temp.p);
				}
				return *this;
			}

			template<typename SRC>
			void set_proxy(const SRC& src)
			{
				Object* temp;
				src->_copy_to_ref(temp);
				SYNC::swap(p, temp)->_unlock();
			}

			void reset() no_throw
			{
				SYNC::swap(p, NULL)->_unlock();
			}

			template<typename BASE>
			operator const weak<BASE, SYNC>& () const no_throw
			{
				BASE* t_should_be_convertible_to_base = static_cast<T*>(NULL);
				t_should_be_convertible_to_base = t_should_be_convertible_to_base;
				return reinterpret_cast<const weak<BASE, SYNC>&>(*this);
			}
			friend int compare(const weak<T>& a, const weak<T>& b)
			{
				return a.p - b.p;
			}
			friend bool operator== (const weak<T>& a, const weak<T>& b)
			{
				return a.p == b.p;
			}
		};

		template<typename T>
		class pin
		{
			Object* p;
		public:
			pin() no_throw :p() {}
			pin(const pin<T>& src) no_throw
				: p(src->_lock())
			{}
			pin(const T* src) no_throw
				: p(const_cast<Object*>(src->_lock()))
			{}
			template<typename SYNC>
			pin(const master<T, SYNC>& src) no_throw
				: p(SYNC::lock(src.p)->_lock())
			{}
			template<typename SYNC>
			pin(const weak<T, SYNC>& src) no_throw
				: p(SYNC::lock(src.p)->_get_target())
			{}
			~pin() { p->_unlock(); }

			T* operator-> () const no_throw { return static_cast<T*>(p); }
			operator void* /* bool */ () const no_throw { return p; }

			template<typename SRC>
			pin<T>& operator= (const SRC& src) no_throw
			{
				pin<T> temp(src);
				temp.p = no_sync::swap(p, temp.p);
				return *this;
			}

			pin<T>& operator= (const pin<T>& src) no_throw
			{
				src->_lock();
				p->_unlock();
				p = src.p;
				return *this;
			}

			template<typename BASE>
			operator const pin<BASE>& () const no_throw
			{
				ak::should_be_convertible_to<BASE*>(static_cast<T*>(NULL));
				return reinterpret_cast<const pin<BASE>&>(*this);
			}
			friend int compare(const pin<T>& a, const pin<T>& b)
			{
				return a.p - b.p;
			}
			friend bool operator== (const pin<T>& a, const pin<T>& b)
			{
				return a.p == b.p;
			}
			friend void swap(pin<T>&a, pin<T>& b)
			{
				std::swap(a.p, b.p);
			}
		};

		template<typename DESCENDANT, typename T>
		const pin<DESCENDANT>& cast(const pin<T>& t) no_throw
		{
			T* descendant_should_be_convertible_to_t = static_cast<DESCENDANT*>(NULL);
			return reinterpret_cast<const pin<DESCENDANT>&>(t);
		}
		template<typename DESCENDANT, typename T>
		pin<DESCENDANT>& cast(pin<T>& t) no_throw
		{
			T* descendant_should_be_convertible_to_t = static_cast<DESCENDANT*>(NULL);
			return reinterpret_cast<pin<DESCENDANT>&>(t);
		}

		template<typename DESCENDANT, typename T, typename SYNC>
		const master<DESCENDANT, SYNC>& cast(const master<T, SYNC>& t) no_throw
		{
			T* descendant_should_be_convertible_to_t = static_cast<DESCENDANT*>(NULL);
			return reinterpret_cast<const master<DESCENDANT, SYNC>&>(t);
		}
		template<typename DESCENDANT, typename T, typename SYNC>
		master<DESCENDANT, SYNC>& cast(master<T, SYNC>& t) no_throw
		{
			T* descendant_should_be_convertible_to_t = static_cast<DESCENDANT*>(NULL);
			return reinterpret_cast<master<DESCENDANT, SYNC>&>(t);
		}

		template<typename DESCENDANT, typename T, typename SYNC>
		const weak<DESCENDANT, SYNC>& cast(const weak<T, SYNC>& t) no_throw
		{
			T* descendant_should_be_convertible_to_t = static_cast<DESCENDANT*>(NULL);
			return reinterpret_cast<const weak<DESCENDANT, SYNC>&>(t);
		}
		template<typename DESCENDANT, typename T, typename SYNC>
		weak<DESCENDANT, SYNC>& cast(weak<T, SYNC>& t) no_throw
		{
			T* descendant_should_be_convertible_to_t = static_cast<DESCENDANT*>(NULL);
			return reinterpret_cast<weak<DESCENDANT, SYNC>&>(t);
		}

		template<typename A, typename B>
		bool operator!= (const A& a, const B& b)
		{
			return !(a == b);
		}
		template <typename T>
		inline void unsafe_swap(master<T>& a, master<T>& b)
		{
			Object* t = a.p;
			a.p = b.p;
			b.p = t;
		}

		template <typename T>
		inline int compare(const master<T>& a, const master<T>& b)
		{
			return a.p - b.p;
		}

		template <typename T>
		inline bool operator== (const master<T>& a, const master<T>& b)
		{
			return a.p == b.p;
		}

	}
}

#endif // _AK_LTM_H_
